home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OWLSRC.PAK / DOCUMENT.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  16.0 KB  |  777 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows
  3. // Copyright (c) 1993, 1997 by Borland International, All Rights Reserved
  4. //
  5. //$Revision:   10.17  $
  6. //
  7. // Implementation of class TDocument
  8. //----------------------------------------------------------------------------
  9. #pragma hdrignore SECTION
  10. #include <owl/pch.h>
  11. #if !defined(OWL_DOCMANAG_H)
  12. # include <owl/docmanag.h>
  13. #endif
  14. #if !defined(OWL_APPDICT_H)
  15. # include <owl/appdict.h>
  16. #endif
  17. #if !defined(OWL_DOCVIEW_RH)
  18. # include <owl/docview.rh>
  19. #endif
  20. #include <string.h>
  21. #include <stdio.h>
  22.  
  23. OWL_DIAGINFO;
  24. DIAG_DECLARE_GROUP(OwlDocView);        // General Doc/View diagnostic group
  25.  
  26. //    of index between multiple applications.
  27. // int TDocument::UntitledIndex = 0;
  28.  
  29. #if !defined(SECTION) || SECTION == 1
  30.  
  31. //
  32. //
  33. //
  34. TDocument::TDocument(TDocument* parent)
  35. :
  36.   ParentDoc(parent),
  37.   NextDoc(0), OpenMode(0),
  38.   Title(0), Template(0),
  39.   ViewList(0), Tag(0), StreamList(0),
  40.   DocPath(0),
  41.   DirtyFlag(false), Embedded(false)
  42. {
  43.   if (parent) {
  44.     DocManager = parent->DocManager;
  45.  
  46.     // Handle case of 'dummy' parent [parent parented to itself] which was
  47.     // created by the docmanager simply to pass itself to us
  48.     //
  49.     if (parent->ParentDoc == parent) {
  50.       ParentDoc = 0;
  51.       CHECK(DocManager);
  52.       DocManager->DocList.Insert(this);
  53.     }
  54.     else
  55.       parent->ChildDoc.Insert(this);
  56.   }
  57.   else {
  58.     TApplication* app = GetApplicationObject();
  59.     CHECK(app);
  60.     DocManager = app->DocManager;
  61.     if (!DocManager)
  62.       TXOwl::Raise(IDS_NODOCMANAGER);  // No doc manager to catch this one
  63.     DocManager->DocList.Insert(this);
  64.   }
  65. }
  66.  
  67. //
  68. //
  69. //
  70. TDocument::~TDocument()
  71. {
  72.   // Is this a dummy document?
  73.   //
  74.   if (ParentDoc == this)
  75.     return;
  76.  
  77.   // Unref template - prevents self autodelete when deleting views, including
  78.   // views in child documents
  79.   //
  80.   SetTemplate(0);
  81.  
  82.   // Destroy children first if we have any. Then force close here as a last
  83.   // resort if derived classes have not done so. Since we have destructed down
  84.   // to a TDocument by now, derived closes will not be called.
  85.   //
  86.   ChildDoc.Destroy();
  87.   Close();
  88.  
  89.   // NOTE: View's destructor invokes 'DetachView' which removes it from
  90.   //       the list
  91.   //
  92.   while (ViewList)
  93.     delete ViewList;
  94.  
  95.   // Delete all streams, should only be present if abort or coding error
  96.   //
  97.   while (StreamList) {
  98.     TRACEX(OwlDocView, 0, "~TDocument(): StreamList not 0!");
  99.     delete StreamList;
  100.   }
  101.  
  102.   // Detach from parent and doc manager
  103.   //
  104.   if (ParentDoc) {
  105.     ParentDoc->ChildDoc.Remove(this);
  106.   }
  107.   else {
  108.     CHECK(DocManager);
  109.     DocManager->PostEvent(dnClose, *this);
  110.     DocManager->DocList.Remove(this);
  111.   }
  112.  
  113.   delete[] Title;
  114.   delete[] DocPath;
  115. }
  116.  
  117. //
  118. //
  119. //
  120. static char* PropNames[] = {
  121.   "Document Class",  // DocumentClass
  122.   "Template Name",   // TemplateName
  123.   "View Count",      // ViewCount
  124.   "Storage Path",    // StoragePath
  125.   "Document Title",  // DocTitle
  126. };
  127.  
  128. //
  129. //
  130. //
  131. static int PropFlags[] = {
  132.   pfGetText|pfConstant,  // DocumentClass
  133.   pfGetText,             // TemplateName
  134.   pfGetBinary|pfGetText, // ViewCount
  135.   pfGetText|pfSettable,  // StoragePath
  136.   pfGetText|pfSettable,  // DocTitle
  137. };
  138.  
  139. //
  140. //
  141. //
  142. const char*
  143. TDocument::PropertyName(int index)
  144. {
  145.   if (index <= PrevProperty) {
  146.     TRACEX(OwlDocView, 0, "PropertyName(): index <= PrevProperty!");
  147.     return 0;
  148.   }
  149.   else if (index < NextProperty)
  150.     return PropNames[index-PrevProperty-1];
  151.   else {
  152.     TRACEX(OwlDocView, 0, "PropertyName(): index >= PrevProperty!");
  153.     return 0;
  154.   }
  155. }
  156.  
  157. //
  158. //
  159. //
  160. int
  161. TDocument::PropertyFlags(int index)
  162. {
  163.   if (index <= PrevProperty) {
  164.     TRACEX(OwlDocView, 0, "PropertyFlags(): index <= PrevProperty!");
  165.     return 0;
  166.   }
  167.   else if (index < NextProperty)
  168.     return PropFlags[index-PrevProperty-1];
  169.   else {
  170.     TRACEX(OwlDocView, 0, "PropertyFlags(): index >= PrevProperty!");
  171.     return 0;
  172.   }
  173. }
  174.  
  175. //
  176. //
  177. //
  178. int
  179. TDocument::FindProperty(const char far* name)
  180. {
  181.   int i;
  182.   for (i=0; i < NextProperty-PrevProperty-1; i++)
  183.     if (strcmp(PropNames[i], name) == 0)
  184.       return i+PrevProperty+1;
  185.  
  186.   TRACEX(OwlDocView, 0, "FindProperty(): " \
  187.         "index of [" << string(name) << "] not found" );
  188.   return 0;
  189. }
  190.  
  191. //
  192. //
  193. //
  194. int
  195. TDocument::GetProperty(int prop, void far* dest, int textlen)
  196. {
  197.   const char far* src;
  198.   char numBuf[15];
  199.   switch (prop) {
  200.     case DocumentClass:
  201.       src = _TYPENAME(this);
  202.       break;
  203.  
  204.     case TemplateName:
  205.       src = Template ? Template->GetDescription() : 0;
  206.       break;
  207.  
  208.     case ViewCount: {
  209.       int cnt;
  210.       TView* view;
  211.       for (view=ViewList, cnt=0; view != 0; view=view->NextView, cnt++)
  212.         ; // Do nothing
  213.       if (!textlen) {
  214.         *(int far*)dest = cnt;
  215.         return sizeof(int);
  216.       }
  217.       sprintf(numBuf, "%d", cnt);
  218.       src = numBuf;
  219.       break;
  220.     }
  221.  
  222.     case StoragePath:
  223.       src = DocPath;
  224.       break;
  225.  
  226.     case DocTitle:
  227.       src = Title;
  228.       break;
  229.  
  230.     default:
  231.       TRACEX(OwlDocView, 0, "GetProperty(): " \
  232.             "invalid property [" << prop << "] specified!" );
  233.       return 0;
  234.   }
  235.  
  236.   if (!textlen) {
  237.     TRACEX(OwlDocView, 0, "GetProperty(): 0-Length buffer specified!");
  238.     return 0;
  239.   }
  240.   int srclen = src ? strlen(src) : 0;
  241.   if (textlen > srclen)
  242.     textlen = srclen;
  243.   if (textlen)
  244.     memcpy(dest, src, textlen);
  245.   *((char far*)dest + textlen) = 0;
  246.   return srclen;
  247. }
  248.  
  249. //
  250. //
  251. //
  252. bool
  253. TDocument::SetProperty(int prop, const void far* src)
  254. {
  255.   switch (prop) {
  256.     case DocTitle:
  257.       SetTitle((const char far*)src);
  258.       break;
  259.  
  260.     case StoragePath:
  261.       return SetDocPath((const char far*)src);
  262.  
  263.     default:
  264.       TRACEX(OwlDocView, 0, "SetProperty(): invalid prop [" << prop <<\
  265.             "] specified!");
  266.       return false;
  267.   }
  268.   return true;
  269. }
  270.  
  271. //
  272. //
  273. //
  274. TDocument&
  275. TDocument::RootDocument()
  276. {
  277.   TDocument* pdoc = this;
  278.   while (pdoc->ParentDoc)
  279.     pdoc = pdoc->ParentDoc;
  280.   return *pdoc;
  281. }
  282.  
  283. //
  284. //
  285. //
  286. void
  287. TDocument::SetDocManager(TDocManager& dm)
  288. {
  289.   if (!ParentDoc) {
  290.     if (DocManager)  // test needed for TDocManager::Streamer::Read()
  291.       DocManager->DocList.Remove(this);
  292.     dm.DocList.Insert(this);
  293.   }
  294.   DocManager = &dm;
  295. }
  296.  
  297. //
  298. //
  299. //
  300. bool
  301. TDocument::SetDocPath(const char far* path)
  302. {
  303.   // Path has been set already
  304.   //
  305.   if (path && (path == DocPath)) {
  306.     TRACEX(OwlDocView, 0, "SetDocPath(): path [" << string(path) << "] "\
  307.                           "already set!");
  308.     return true;
  309.   }
  310.  
  311.   delete[] DocPath;
  312.   DocPath = (path && *path) ? strnewdup(path) : 0;
  313.  
  314.   char title[_MAX_PATH] = "Unknown";  // Never used - but just in case!
  315.   if (!DocPath || ::GetFileTitle(DocPath, title, sizeof title) != 0) {
  316.     CHECK(DocManager);
  317.     CHECK(DocManager->GetApplication());
  318.  
  319.     int len = DocManager->GetApplication()->LoadString(IDS_UNTITLED,
  320.                                                        title, sizeof title);
  321.     if (DocManager->IsFlagSet(dmMDI))
  322.       sprintf(title+len, "%d", ++(DocManager->GetUntitledIndex()));
  323.   }
  324.   SetTitle(title);
  325.   return true;  // derived classes may validate path
  326. }
  327.  
  328. //
  329. //
  330. //
  331. void
  332. TDocument::SetTitle(const char far* title)
  333. {
  334.   delete[] Title;
  335.   Title = title ? strnewdup(title) : 0;
  336.   ReindexFrames();
  337. }
  338.  
  339. //
  340. //
  341. //
  342. bool
  343. TDocument::SetTemplate(TDocTemplate* tpl)
  344. {
  345.   if (Template) {
  346.     CHECK(DocManager);
  347.     DocManager->UnRefTemplate(*Template);
  348.   }
  349.   if (tpl) {
  350.     CHECK(DocManager);
  351.     DocManager->RefTemplate(*tpl);
  352.   }
  353.   Template = tpl;
  354.   return true;
  355. }
  356.  
  357. //
  358. //
  359. //
  360. void
  361. TDocument::ReindexFrames()
  362. {
  363.   TView* view;
  364.   int seq;
  365.  
  366.   for (seq = -1, view = ViewList; view != 0; view = view->NextView) {
  367.     seq -= view->SetDocTitle(Title, seq);  // decrement if title displayed
  368.     if (seq == -3)   // need only check if more than one title displayed
  369.       break;
  370.   }
  371.   if (seq == -1)
  372.     return;
  373.   seq = (seq == -2 ? 0 : 1);
  374.   for (view = ViewList; view != 0; view = view->NextView) {
  375.     seq += view->SetDocTitle(Title, seq);  // increment if title displayed
  376.   }
  377. }
  378.  
  379. //
  380. //
  381. //
  382. void
  383. TDocument::AttachStream(TStream& strm)
  384. {
  385.   strm.NextStream = StreamList;
  386.   StreamList = &strm;
  387. }
  388.  
  389. //
  390. //
  391. //
  392. void
  393. TDocument::DetachStream(TStream& strm)
  394. {
  395.   TStream** plist = &StreamList;
  396.   for ( ; *plist; plist = &(*plist)->NextStream) {
  397.     if (*plist == &strm) {
  398.       *plist = strm.NextStream;
  399.       return;
  400.     }
  401.   }
  402. }
  403.  
  404. //
  405. //
  406. //
  407. TStream*
  408. TDocument::NextStream(const TStream* strm)
  409. {
  410.   return strm ? strm->NextStream : StreamList;
  411. }
  412.  
  413. //
  414. //
  415. //
  416. TView*
  417. TDocument::NextView(const TView* view)
  418. {
  419.   return view ? view->NextView : ViewList;
  420. }
  421.  
  422. //
  423. //
  424. //
  425. void
  426. TDocument::AttachView(TView& view)
  427. {
  428.   TView** ppview;
  429.  
  430.   for (ppview = &ViewList; *ppview; ppview = &(*ppview)->NextView)
  431.     ;
  432.   *ppview = &view;    // insert at end of list
  433.   view.NextView = 0;
  434.   view.Doc = this;
  435.   NotifyViews(vnViewOpened, (long)&view, &view);
  436. }
  437.  
  438. //
  439. //
  440. //
  441. TView*
  442. TDocument::InitView(TView* view)
  443. {
  444.   if (!view) {
  445.     TRACEX(OwlDocView, 0, "InitView(): 0 view specified!");
  446.     return 0;
  447.   }
  448.   if (!view->IsOK()) {
  449.     TRACEX(OwlDocView, 0, "InitView(): Invalid view object specified!");
  450.     delete view;
  451.     return 0;
  452.   }
  453.  
  454.   CHECK(DocManager);
  455.   DocManager->PostEvent(dnCreate, *view);
  456.  
  457.   if (!view->IsOK()) {
  458.     TRACEX(OwlDocView, 0, "InitView(): Invalid view object post dnCreate!");
  459.     delete view;
  460.     return 0;
  461.   }
  462.  
  463.   ReindexFrames();
  464.   TView::BumpNextViewId();
  465.  
  466.   return view;
  467. }
  468.  
  469. //
  470. // DetachView is invoked from TView's destructor so that the view can detach
  471. // itself from this document. True is returned if the detachment is successful
  472. // indicating that this document should be deleted.
  473. //
  474. bool
  475. TDocument::DetachView(TView& view)
  476. {
  477.   TView** plist = &ViewList;
  478.   for (; *plist; plist = &(*plist)->NextView) {
  479.     if (*plist == &view) {
  480.  
  481.       // Found the view, now detach it and notify app and other views
  482.       //
  483.       DocManager->PostEvent(dnClose, view);
  484.       *plist = view.NextView;
  485.       NotifyViews(vnViewClosed, (long)&view, &view);
  486.  
  487.       // Cleanup doc if last view was just closed and dtAutoDelete
  488.       // or dtAutoOpen is set. dtAutoOpen will cause an autoclose, while
  489.       // dtAutoDelete will delete this doc also.
  490.       //
  491.       if (!ViewList) {
  492.         if (Template && ((Template->Flags & dtAutoDelete) ||
  493.                          (Template->Flags & dtAutoOpen))) {
  494.           // Close document streams
  495.           //
  496.           if (IsOpen())
  497.             Close();
  498.  
  499.           // Returning true will cause ~TView to delete document. Using
  500.           // 'view.IsOK()' caters for cases where TView's construction failed.
  501.           //
  502.           return (Template->Flags & dtAutoDelete) && view.IsOK();
  503.         }
  504.       }
  505.       else {
  506.         ReindexFrames();
  507.       }
  508.       break;
  509.     }
  510.   }
  511.   return false;
  512. }
  513.  
  514. //
  515. //
  516. //
  517. bool
  518. TDocument::Commit(bool force)
  519. {
  520.   TDocument* pdoc = 0;
  521.   while ((pdoc = ChildDoc.Next(pdoc)) != 0) {
  522.     if (!pdoc->Commit(force))
  523.       return false;
  524.   }
  525.  
  526.   WARNX(OwlDocView, !DocPath, 0, "Commit(): 0 DocPath!");
  527.   return NotifyViews(vnCommit, force);
  528. }
  529.  
  530. //
  531. //
  532. //
  533. bool
  534. TDocument::Revert(bool clear)
  535. {
  536.   TDocument* pdoc = 0;
  537.   while ((pdoc = ChildDoc.Next(pdoc)) != 0) {
  538.     if (!pdoc->Revert(clear))
  539.       return false;
  540.   }
  541.   return NotifyViews(vnRevert, clear);
  542. }
  543.  
  544. //
  545. //
  546. //
  547. bool
  548. TDocument::NotifyViews(int event, long item, TView* exclude)
  549. {
  550.   bool answer = true;
  551.  
  552.   TDocument* pdoc = 0;
  553.   while ((pdoc = ChildDoc.Next(pdoc)) != 0)
  554.     answer = (answer && pdoc->NotifyViews(event, item, exclude)) != 0;
  555.  
  556.   TEventHandler::TEventInfo eventInfo(WM_OWLNOTIFY, event);
  557.   for (TView* view = ViewList; view != 0; view = view->NextView)
  558.     if (view != exclude && view->Find(eventInfo))
  559.       answer = (answer && view->Dispatch(eventInfo, 0, item)) != 0;
  560.  
  561.   return answer;
  562. }
  563.  
  564. //
  565. //
  566. //
  567. TView*
  568. TDocument::QueryViews(int event, long item, TView* exclude)
  569. {
  570.   TView* view;
  571.   TDocument* pdoc = 0;
  572.   while ((pdoc = ChildDoc.Next(pdoc)) != 0)
  573.     if ((view = pdoc->QueryViews(event, item, exclude)) != 0)
  574.       return view;
  575.  
  576.   TEventHandler::TEventInfo eventInfo(WM_OWLNOTIFY, event);
  577.   for (view = ViewList; view != 0; view = view->NextView) {
  578.     if (view != exclude) {
  579.       if (view->Find(eventInfo)) {
  580.         if (view->Dispatch(eventInfo, 0, item)) {
  581.           return view;            // Return first acknowledger
  582.         }
  583.       }
  584.     }
  585.   }
  586.   return 0;           
  587. }
  588.  
  589. //
  590. //
  591. //
  592. bool
  593. TDocument::IsDirty()
  594. {
  595.   if (DirtyFlag)
  596.     return true;
  597.  
  598.   TDocument* pdoc = 0;
  599.   while ((pdoc = ChildDoc.Next(pdoc)) != 0)
  600.     if (pdoc->IsDirty())
  601.       return true;
  602.  
  603.   return QueryViews(vnIsDirty) != 0;
  604. }
  605.  
  606. //
  607. //
  608. //
  609. bool
  610. TDocument::HasFocus(HWND hWnd)
  611. {
  612.   return DocWithFocus(hWnd) != 0;
  613. }
  614.  
  615. //
  616. // Return pointer to this document or one of its child documents if the 
  617. // spcecified window parameter is a view associated with the document.
  618. // NOTE: Unlike 'HasFocus', this method allows you to distinguish whether
  619. //       the document with focus is a child document.
  620. //
  621. TDocument*
  622. TDocument::DocWithFocus(HWND hWnd)
  623. {
  624.   TDocument* pdoc = 0;
  625.   while ((pdoc = ChildDoc.Next(pdoc)) != 0)
  626.     if (pdoc->DocWithFocus(hWnd))
  627.       return pdoc;
  628.  
  629.   return QueryViews(vnIsWindow, (long)hWnd) ? this : 0;
  630. }
  631.  
  632. //
  633. //
  634. //
  635. bool
  636. TDocument::CanClose()
  637. {
  638.   TDocument* pdoc = 0;
  639.   while ((pdoc = ChildDoc.Next(pdoc)) != 0)
  640.     if (!pdoc->CanClose())
  641.       return false;
  642.  
  643.   return DocManager->FlushDoc(*this);  // do the UI in the doc manager
  644. }
  645.  
  646. //
  647. //
  648. //
  649. bool
  650. TDocument::Close()
  651. {
  652.   TDocument* pdoc = 0;
  653.   while ((pdoc = ChildDoc.Next(pdoc)) != 0)
  654.     if (!pdoc->Close())
  655.       return false;
  656.  
  657.   return true;
  658. }
  659.  
  660. //
  661. //
  662. //
  663. uint
  664. TDocument::PostError(uint sid, uint choice)
  665. {
  666.   return DocManager->PostDocError(*this, sid, choice);
  667. }
  668.  
  669. //----------------------------------------------------------------------------
  670.  
  671. //
  672. //
  673. //
  674. TDocument*
  675. TDocument::TList::Next(const TDocument* doc)
  676. {
  677.   return doc ? doc->NextDoc : DocList;
  678. }
  679.  
  680. //
  681. //
  682. //
  683. bool
  684. TDocument::TList::Insert(TDocument* doc)
  685. {
  686.   TDocument* pdoc;
  687.   for (pdoc = DocList; pdoc; pdoc = pdoc->NextDoc)
  688.     if (pdoc == doc)
  689.       return false;
  690.   doc->NextDoc = DocList;
  691.   DocList = doc;
  692.   return true;
  693. }
  694.  
  695. //
  696. //
  697. //
  698. bool
  699. TDocument::TList::Remove(TDocument* doc)
  700. {
  701.   TDocument** ppdoc;
  702.   for (ppdoc = &DocList; *ppdoc; ppdoc = &(*ppdoc)->NextDoc) {
  703.     if (*ppdoc == doc) {
  704.       *ppdoc = doc->NextDoc;
  705.       return true;
  706.     }
  707.   }
  708.   return false;
  709. }
  710.  
  711. //
  712. //
  713. //
  714. void
  715. TDocument::TList::Destroy()
  716. {
  717.   while (DocList)
  718.     delete DocList;   // removes it entry from destructor
  719. }
  720.  
  721. #endif
  722. //----------------------------------------------------------------------------
  723. #if !defined(SECTION) || SECTION == 2
  724.  
  725. IMPLEMENT_ABSTRACT_STREAMABLE(TDocument);
  726.  
  727. #if !defined(BI_NO_OBJ_STREAMING)
  728.  
  729. //
  730. //
  731. //
  732. void*
  733. TDocument::Streamer::Read(ipstream& is, uint32 /*version*/) const
  734. {
  735.   TDocument* o = GetObject();
  736.  
  737.   o->NextDoc = 0;
  738.   o->StreamList = 0;
  739.   o->DocManager = 0;
  740.   o->DirtyFlag = false;
  741.  
  742.   is >> o->OpenMode;
  743.   o->DocPath = is.freadString();
  744.   o->Title   = is.freadString();
  745.   is >> o->Template;  // static templates must have been already streamed
  746.   is >> o->ParentDoc;
  747.   o->ViewList = 0;    // must init, does not get set until after view streamed
  748.   is >> o->ViewList;
  749.  
  750.   is >> TView::NextViewId;  // static, but must get set by at least 1 document
  751.  
  752.   return o;
  753. }
  754.  
  755. //
  756. //
  757. //
  758. void
  759. TDocument::Streamer::Write(opstream& os) const
  760. {
  761.   TDocument* o = GetObject();
  762.  
  763.   while (!o->CanClose())   // can't permit cancel here
  764.     ;
  765.   os << o->OpenMode;
  766.   os.fwriteString(o->DocPath);
  767.   os.fwriteString(o->Title);
  768.   os << o->Template;       // templates already streamed, must be so if static
  769.   os << o->ParentDoc;
  770.   os << o->ViewList;       // each view streams out the next
  771.   os << TView::NextViewId; // insure that this static var gets set on reload
  772. }
  773.  
  774. #endif  // if !defined(BI_NO_OBJ_STREAMING)
  775.  
  776. #endif
  777.